package org.microframework.base.core.security.token;

import java.security.Key;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.spec.SecretKeySpec;
import org.microframework.base.core.security.model.LoginUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

/**
 * Token解析器
 * 
 * 用于创建和解析JWT令牌
 */
@Component
public class TokenParser {
    
    private static final Logger log = LoggerFactory.getLogger(TokenParser.class);
    
    /**
     * 令牌秘钥
     */
    @Value("${token.secret:abcdefghijklmnopqrstuvwxyz}")
    private String secret;
    
    /**
     * 令牌有效期（默认30分钟）
     */
    @Value("${token.expireTime:30}")
    private int expireTime;
    
    /**
     * 创建令牌
     * 
     * @param loginUser 用户信息
     * @return 令牌
     */
    public String createToken(LoginUser loginUser) {
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * 60 * 1000);
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", loginUser.getUserId());
        claims.put("username", loginUser.getUsername());
        claims.put("realName", loginUser.getRealName());
        claims.put("admin", loginUser.isAdmin());
        return createToken(claims);
    }
    
    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private String createToken(Map<String, Object> claims) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        
        // 生成签名密钥
        byte[] apiKeySecretBytes = Base64.getDecoder().decode(secret);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName());
        
        // 添加构成JWT的参数
        JwtBuilder builder = Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .signWith(SignatureAlgorithm.HS256, signingKey);
        
        // 添加Token过期时间
        long expMillis = nowMillis + expireTime * 60 * 1000;
        Date exp = new Date(expMillis);
        builder.setExpiration(exp);
        
        return builder.compact();
    }
    
    /**
     * 验证令牌有效性
     *
     * @param token 令牌
     * @return 是否有效
     */
    public boolean validateToken(String token) {
        try {
            Claims claims = parseToken(token);
            return claims != null && !isTokenExpired(claims);
        } catch (Exception e) {
            log.error("验证Token失败: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 解析JWT
     *
     * @param token JWT
     * @return 数据声明
     */
    public Claims parseToken(String token) {
        try {
            byte[] apiKeySecretBytes = Base64.getDecoder().decode(secret);
            Key signingKey = new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName());
            
            return Jwts.parser()
                    .setSigningKey(signingKey)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            log.error("解析Token失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 从令牌中获取用户ID
     *
     * @param token 令牌
     * @return 用户ID
     */
    public Long getUserIdFromToken(String token) {
        Claims claims = parseToken(token);
        return claims == null ? null : Long.valueOf(claims.get("userId").toString());
    }
    
    /**
     * 从令牌中获取用户名
     *
     * @param token 令牌
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        Claims claims = parseToken(token);
        return claims == null ? null : claims.get("username").toString();
    }
    
    /**
     * 从令牌中获取用户真实姓名
     *
     * @param token 令牌
     * @return 用户真实姓名
     */
    public String getRealNameFromToken(String token) {
        Claims claims = parseToken(token);
        return claims == null ? null : claims.get("realName").toString();
    }
    
    /**
     * 从令牌中获取是否为管理员
     *
     * @param token 令牌
     * @return 是否为管理员
     */
    public Boolean isAdminFromToken(String token) {
        Claims claims = parseToken(token);
        return claims == null ? false : Boolean.valueOf(claims.get("admin").toString());
    }
    
    /**
     * 判断令牌是否过期
     *
     * @param claims 声明
     * @return 是否过期
     */
    private boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }
} 